// basic sound volume control program version 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alsa/asoundlib.h>

// Adjust volume (positive for up, negative for down; step in percentage)
int adjust_volume(int step) {
    snd_mixer_t *mixer;
    snd_mixer_selem_id_t *sid;
    const char *card = "default";  // Default sound card
    const char *selem_name = "Master";  // Master channel (adjust if needed)
    long min, max;
    long vol;
    int err;

    // Initialize mixer
    if ((err = snd_mixer_open(&mixer, 0)) < 0) {
        fprintf(stderr, "Cannot open mixer: %s\n", snd_strerror(err));
        return err;
    }

    if ((err = snd_mixer_attach(mixer, card)) < 0) {
        fprintf(stderr, "Cannot attach mixer to card: %s\n", snd_strerror(err));
        snd_mixer_close(mixer);
        return err;
    }

    if ((err = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) {
        fprintf(stderr, "Cannot register mixer element: %s\n", snd_strerror(err));
        snd_mixer_close(mixer);
        return err;
    }

    // Load mixer elements
    if ((err = snd_mixer_load(mixer)) < 0) {
        fprintf(stderr, "Cannot load mixer elements: %s\n", snd_strerror(err));
        snd_mixer_close(mixer);
        return err;
    }

    // Find the master channel (selem = sound element)
    snd_mixer_selem_id_alloca(&sid);
    snd_mixer_selem_id_set_index(sid, 0);
    snd_mixer_selem_id_set_name(sid, selem_name);
    snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer, sid);
    if (!elem) {
        fprintf(stderr, "Cannot find mixer element: %s\n", selem_name);
        snd_mixer_close(mixer);
        return -1;
    }

    // Get volume range (min/max values)
    if ((err = snd_mixer_selem_get_playback_volume_range(elem, &min, &max)) < 0) {
        fprintf(stderr, "Cannot get volume range: %s\n", snd_strerror(err));
        snd_mixer_close(mixer);
        return err;
    }

    // Get current volume (for front left/right; adjust if using mono)
    if ((err = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &vol)) < 0) {
        fprintf(stderr, "Cannot get current volume: %s\n", snd_strerror(err));
        snd_mixer_close(mixer);
        return err;
    }

    // Calculate new volume (step is percentage of total range)
    long range = max - min;
    long step_abs = (range * abs(step)) / 100;  // Convert % to ALSA's volume units
    long new_vol = (step > 0) ? vol + step_abs : vol - step_abs;

    // Clamp volume to [min, max] range
    if (new_vol > max) new_vol = max;
    if (new_vol < min) new_vol = min;

    // Apply new volume to both front left and right channels
    if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, new_vol)) < 0) {
        fprintf(stderr, "Failed to set left channel volume: %s\n", snd_strerror(err));
        snd_mixer_close(mixer);
        return err;
    }
    if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, new_vol)) < 0) {
        fprintf(stderr, "Failed to set right channel volume: %s\n", snd_strerror(err));
        snd_mixer_close(mixer);
        return err;
    }

    // Cleanup
    snd_mixer_close(mixer);
    return 0;
}

int main(int argc, char *argv[]) {
#ifndef STEP
#define STEP 5
#endif
    if (argc != 2) {
	fprintf(stderr, "\n%s is a program for controling your sound volume by STEP %d(default)\n", argv[0], STEP);
        fprintf(stderr, "\nUsage: %s [up|down]\n", argv[0]);
        return 1;
    }

    // const int STEP = 5;  // 5% volume change per step
    int ret;

    if (strcmp(argv[1], "up") == 0) {
        ret = adjust_volume(STEP);
    } else if (strcmp(argv[1], "down") == 0) {
        ret = adjust_volume(-STEP);
    } else {
        fprintf(stderr, "Invalid argument: use 'up' or 'down'\n");
        return 1;
    }

    return ret;
}
